WOLF core
WOLF: A Modular Estimation Framework for Robotics
XXXXXXXXXXXXXXXXXXXXXXXXvoid(0)" frameborder="0" name="MSearchResults" id="MSearchResults">
SE3.h
Go to the documentation of this file.
1// WOLF - Copyright (C) 2020-2026
2// Institut de Robòtica i Informàtica Industrial, CSIC-UPC.
3// Authors: Joan Solà Ortega (jsola@iri.upc.edu) and
4// Joan Vallvé Navarro (jvallve@iri.upc.edu)
5// All rights reserved.
6//
7// This file is part of WOLF: http://www.iri.upc.edu/wolf
8// WOLF is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License version 3
10// as published by the Free Software Foundation.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19#pragma once
20
21#include "core/common/wolf.h"
22#include "core/math/rotations.h"
24
25/*
26 * The functions in this file are related to manipulations of Delta motion magnitudes used in 3d motion.
27 *
28 * The Delta is defined as a simple 3d pose with the rotation expressed in quaternion form,
29 * Delta = [Dp, Dq]
30 * with
31 * Dp : position delta
32 * Dq : quaternion delta
33 * and its tangent vector (Lie algebra) is tau = [rho, theta].
34 *
35 * The functions are listed below:
36 *
37 * - identity: I = Delta at the origin, with Dp = [0,0,0]; Dq = [0,0,0,1], so that D (+) I = I (+) D = D
38 * - inverse: so that D (+) D.inv = D.inv (+) D = I
39 * - compose: Dc = D1 (+) D2
40 * - between: Db = D2 (-) D1 := D1.inv (+) D2, so that D2 = D1 (+) Db
41 * - exp: go from tangent space to delta manifold (SE(3) exponential map)
42 * - log: go from delta manifold to tangent space (SE(3) logarithmic map)
43 * - plus: block-wise: D2 = [Dp1 + dp, Dq1 * exp_q(do)]
44 * - minus: block-wise: d = [Dp2 - Dp1, log_q(Dq1.conj * Dq2)], so that D2 = plus(D1, d)
45 * - interpolate: D = D1 (+) exp( t * log( D1.inv (+) D2 ) )
46 * - toSE3: 4x4 homogeneous matrix
47 * - jac_SE3_left, jac_SE3_right, jac_SE3_left_inv, jac_SE3_right_inv: Jacobians of SE(3)
48 *
49 * Each function is provided (when applicable) with the following APIs:
50 * - by parts, with the rotation as a quaternion (Eigen::QuaternionBase)
51 * - by parts, with the rotation as a vector (quaternion coefficients [x, y, z, w])
52 * - full 7-vector [p, q] as output parameter and as return value
53 * - full 7-vector with Jacobians. Jacobians are block-wise: w.r.t. perturbations [dp, do] with additive dp
54 * and local (right) do on the quaternion, i.e. consistent with plus() and minus().
55 * - VectorComposite with keys 'P' and 'O', as output parameter and as return value
56 *
57 * ------------------------------------------------------------------------------------------
58 *
59 * Some of the functions below are based on:
60 *
61 * [1] J. Sola et. al. "A micro Lie theory for state estimation in robotics", tech rep. IRI 2018,
62 * https://arxiv.org/pdf/1812.01537.pdf
63 */
64
65namespace wolf
66{
67namespace SE3
68{
69using namespace Eigen;
70
72// JACOBIANS OF SE(3)
73
84template <typename D1, typename D2>
85inline Matrix<typename D1::Scalar, 3, 3> Q_helper(const MatrixBase<D1>& v, const MatrixBase<D2>& w)
86{
87 typedef typename D1::Scalar T;
88
89 Matrix<T, 3, 3> V = skew(v);
90 Matrix<T, 3, 3> W = skew(w);
91 Matrix<T, 3, 3> WV = W * V, VW = V * W, WW = W * W;
92
93 T th_2 = w.squaredNorm();
94 T c2, c3, c4;
95
96 if (th_2 < T(1e-4)) // th < 1e-2
97 {
98 T th_4 = th_2 * th_2;
99 c2 = T(1. / 6.) - th_2 / T(120.) + th_4 / T(5040.);
100 c3 = T(1. / 24.) - th_2 / T(720.) + th_4 / T(40320.);
101 c4 = T(1. / 120.) - th_2 / T(2520.) + th_4 / T(120960.);
102 }
103 else
104 {
105 T th = sqrt(th_2);
106 T sin_th = sin(th);
107 T cos_th = cos(th);
108 c2 = (th - sin_th) / (th_2 * th);
109 c3 = (th_2 + T(2.0) * cos_th - T(2.0)) / (T(2.0) * th_2 * th_2);
110 c4 = (T(2.0) * th - T(3.0) * sin_th + th * cos_th) / (T(2.0) * th_2 * th_2 * th);
111 }
112
113 Matrix<T, 3, 3> WVW = WV * W;
114 Matrix<T, 3, 3> Q =
115 T(0.5) * V + c2 * (WV + VW + WVW) + c3 * (WW * V + VW * W - T(3.0) * WVW) + c4 * (WVW * W + WW * V * W);
116 return Q;
117}
118
121template <typename D>
122inline Matrix<typename D::Scalar, 6, 6> jac_SE3_left(const MatrixBase<D>& tangent)
123{
125 typedef typename D::Scalar T;
126
127 Matrix<T, 3, 1> v = tangent.template head<3>(); // linear
128 Matrix<T, 3, 1> w = tangent.template tail<3>(); // angular
129
130 Matrix<T, 3, 3> Jl = jac_SO3_left(w);
131
132 Matrix<T, 6, 6> Jl_SE3;
133 Jl_SE3.topLeftCorner(3, 3) = Jl;
134 Jl_SE3.bottomRightCorner(3, 3) = Jl;
135 Jl_SE3.topRightCorner(3, 3) = Q_helper(v, w);
136 Jl_SE3.bottomLeftCorner(3, 3).setZero();
137 return Jl_SE3;
138}
139
142template <typename D>
143inline Matrix<typename D::Scalar, 6, 6> jac_SE3_right(const MatrixBase<D>& tangent)
144{
145 return jac_SE3_left(Matrix<typename D::Scalar, 6, 1>(-tangent));
146}
147
150template <typename D>
151inline Matrix<typename D::Scalar, 6, 6> jac_SE3_left_inv(const MatrixBase<D>& tangent)
152{
154 typedef typename D::Scalar T;
155
156 Matrix<T, 3, 1> v = tangent.template head<3>(); // linear
157 Matrix<T, 3, 1> w = tangent.template tail<3>(); // angular
158
159 Matrix<T, 3, 3> Jl_inv = jac_SO3_left_inv(w);
160
161 Matrix<T, 6, 6> Jl_inv_SE3;
162 Jl_inv_SE3.topLeftCorner(3, 3) = Jl_inv;
163 Jl_inv_SE3.bottomRightCorner(3, 3) = Jl_inv;
164 Jl_inv_SE3.topRightCorner(3, 3) = -Jl_inv * Q_helper(v, w) * Jl_inv;
165 Jl_inv_SE3.bottomLeftCorner(3, 3).setZero();
166 return Jl_inv_SE3;
167}
168
171template <typename D>
172inline Matrix<typename D::Scalar, 6, 6> jac_SE3_right_inv(const MatrixBase<D>& tangent)
173{
174 return jac_SE3_left_inv(Matrix<typename D::Scalar, 6, 1>(-tangent));
175}
176
178// IDENTITY
179
180template <typename D1, typename D2>
181inline void identity(MatrixBase<D1>& p, QuaternionBase<D2>& q)
182{
184 p.setZero();
185 q.setIdentity();
186}
187
188template <typename D1, typename D2>
189inline void identity(MatrixBase<D1>& p, MatrixBase<D2>& q)
190{
193
194 Map<Quaternion<typename D2::Scalar>> mq(&q(0));
195 identity(p, mq);
196}
197
198template <typename D>
199inline void identity(MatrixBase<D>& d)
200{
202
203 Map<Matrix<typename D::Scalar, 3, 1>> p(&d(0));
204 Map<Quaternion<typename D::Scalar>> q(&d(3));
205 identity(p, q);
206}
207
208template <typename T = double>
209inline Matrix<T, 7, 1> identity()
210{
211 Matrix<T, 7, 1> ret;
212 identity(ret);
213 return ret;
214}
215
217{
218 v.clear();
219 v['P'].resize(3);
220 v['O'].resize(4);
221 identity(v['P'], v['O']);
222}
223
225{
227 identity(v);
228 return v;
229}
230
232// INVERSE
233
234template <typename D1, typename D2, typename D4, typename D5>
235inline void inverse(const MatrixBase<D1>& p, const QuaternionBase<D2>& q, MatrixBase<D4>& ip, QuaternionBase<D5>& iq)
236{
239
240 ip = -(q.conjugate() * p);
241 iq = q.conjugate();
242}
243
244template <typename D1, typename D2, typename D4, typename D5>
245inline void inverse(const MatrixBase<D1>& p, const MatrixBase<D2>& q, MatrixBase<D4>& ip, MatrixBase<D5>& iq)
246{
249
250 Map<const Quaternion<typename D2::Scalar>> mq(&q(0));
251 Map<Quaternion<typename D5::Scalar>> miq(&iq(0));
252
253 inverse(p, mq, ip, miq);
254}
255
256template <typename D1, typename D2>
257inline void inverse(const MatrixBase<D1>& d, MatrixBase<D2>& id)
258{
261
262 Map<const Matrix<typename D1::Scalar, 3, 1>> p(&d(0));
263 Map<const Quaternion<typename D1::Scalar>> q(&d(3));
264 Map<Matrix<typename D2::Scalar, 3, 1>> ip(&id(0));
265 Map<Quaternion<typename D2::Scalar>> iq(&id(3));
266
267 inverse(p, q, ip, iq);
268}
269
270template <typename D>
271inline Matrix<typename D::Scalar, 7, 1> inverse(const MatrixBase<D>& d)
272{
273 Matrix<typename D::Scalar, 7, 1> id;
274 inverse(d, id);
275 return id;
276}
277
278inline void inverse(const VectorComposite& v, VectorComposite& c)
279{
280 c['P'].resize(3);
281 c['O'].resize(4);
282 inverse(v.at('P'), v.at('O'), c['P'], c['O']);
283}
284
286{
288 inverse(v, c);
289 return c;
290}
291
293// COMPOSE
294
295template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
296inline void compose(const MatrixBase<D1>& p1,
297 const QuaternionBase<D2>& q1,
298 const MatrixBase<D4>& p2,
299 const QuaternionBase<D5>& q2,
300 MatrixBase<D7>& pc,
301 QuaternionBase<D8>& qc)
302{
306
307 pc = p1 + q1 * p2;
308 qc = q1 * q2; // q here to avoid possible aliasing between d1 and sum
309}
310
311template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
312inline void compose(const MatrixBase<D1>& p1,
313 const MatrixBase<D2>& q1,
314 const MatrixBase<D4>& p2,
315 const MatrixBase<D5>& q2,
316 MatrixBase<D7>& pc,
317 MatrixBase<D8>& qc)
318{
322
323 Map<const Quaternion<typename D2::Scalar>> mq1(&q1(0));
324 Map<const Quaternion<typename D5::Scalar>> mq2(&q2(0));
325 Map<Quaternion<typename D8::Scalar>> mqc(&qc(0));
326
327 compose(p1, mq1, p2, mq2, pc, mqc);
328}
329
330template <typename D1, typename D2, typename D3>
331inline void compose(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& sum)
332{
336
337 Map<const Matrix<typename D1::Scalar, 3, 1>> p1(&d1(0));
338 Map<const Quaternion<typename D1::Scalar>> q1(&d1(3));
339 Map<const Matrix<typename D2::Scalar, 3, 1>> p2(&d2(0));
340 Map<const Quaternion<typename D2::Scalar>> q2(&d2(3));
341 Map<Matrix<typename D3::Scalar, 3, 1>> pc(&sum(0));
342 Map<Quaternion<typename D3::Scalar>> qc(&sum(3));
343
344 compose(p1, q1, p2, q2, pc, qc);
345}
346
347template <typename D1, typename D2>
348inline Matrix<typename D1::Scalar, 7, 1> compose(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
349{
350 Matrix<typename D1::Scalar, 7, 1> ret;
351 compose(d1, d2, ret);
352 return ret;
353}
354
355template <typename D1, typename D2, typename D3, typename D4, typename D5>
356inline void compose(const MatrixBase<D1>& d1,
357 const MatrixBase<D2>& d2,
358 MatrixBase<D3>& sum,
359 MatrixBase<D4>& J_sum_d1,
360 MatrixBase<D5>& J_sum_d2)
361{
367
368 // Some useful temporaries
369 Matrix<typename D1::Scalar, 3, 3> dR1 = q2R(d1.segment(3, 4)); // q1.matrix(); // First Delta, DR
370 Matrix<typename D2::Scalar, 3, 3> dR2 = q2R(d2.segment(3, 4)); // q2.matrix(); // Second delta, dR
371
372 // Jac wrt first delta
373 J_sum_d1.setIdentity(); // dDp'/dDp = dDv'/dDv = I
374 J_sum_d1.block(0, 3, 3, 3).noalias() = -dR1 * skew(d2.head(3)); // dDp'/dDo
375 J_sum_d1.block(3, 3, 3, 3) = dR2.transpose(); // dDo'/dDo
376
377 // Jac wrt second delta
378 J_sum_d2.setIdentity(); //
379 J_sum_d2.block(0, 0, 3, 3) = dR1; // dDp'/p
380 // J_sum_d2.block(3,3,3,3) = Matrix3d::Identity(); // dDo'/ddo = I
381
382 // compose deltas -- done here to avoid aliasing when calling with input `d1` and result `sum` referencing the same
383 // variable
384 compose(d1, d2, sum);
385}
386
387inline void compose(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& c)
388{
389 c['P'].resize(3);
390 c['O'].resize(4);
391 compose(x1.at('P'), x1.at('O'), x2.at('P'), x2.at('O'), c['P'], c['O']);
392}
393
395{
397 compose(x1, x2, c);
398 return c;
399}
400
401// inline void compose(const VectorComposite& x1,
402// const VectorComposite& x2,
403// VectorComposite& c,
404// MatrixComposite& J_c_x1,
405// MatrixComposite& J_c_x2)
406// {
407// // Some useful temporaries
408// const auto R1 = q2R(x1.at('O')); // q1.matrix(); // make temporary
409// const auto& R2 = q2R(x2.at('O')); // q2.matrix(); // do not make temporary, only reference
410
411// // Jac wrt first delta
412// J_c_x1.emplace('P', 'P', Matrix3d::Identity());
413// J_c_x1.emplace('P', 'O', -R1 * skew(x2.at('P')));
414// J_c_x1.emplace('O', 'P', Matrix3d::Zero());
415// J_c_x1.emplace('O', 'O', R2.transpose());
416
417// // Jac wrt second delta
418// J_c_x2.emplace('P', 'P', R1);
419// J_c_x2.emplace('P', 'O', Matrix3d::Zero());
420// J_c_x2.emplace('O', 'P', Matrix3d::Zero());
421// J_c_x2.emplace('O', 'O', Matrix3d::Identity());
422
423// // compose deltas -- done here to avoid aliasing when calling with input `x1` and result `c` referencing the
424// same
425// // variable
426// compose(x1, x2, c);
427// }
428
430// BETWEEN
431
432template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
433inline void between(const MatrixBase<D1>& p1,
434 const QuaternionBase<D2>& q1,
435 const MatrixBase<D4>& p2,
436 const QuaternionBase<D5>& q2,
437 MatrixBase<D7>& p12,
438 QuaternionBase<D8>& q12)
439{
443
444 p12 = q1.conjugate() * (p2 - p1);
445 q12 = q1.conjugate() * q2;
446}
447
448template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
449inline void between(const MatrixBase<D1>& p1,
450 const MatrixBase<D2>& q1,
451 const MatrixBase<D4>& p2,
452 const MatrixBase<D5>& q2,
453 MatrixBase<D7>& p12,
454 MatrixBase<D8>& q12)
455{
459
460 Map<const Quaternion<typename D2::Scalar>> mq1(&q1(0));
461 Map<const Quaternion<typename D5::Scalar>> mq2(&q2(0));
462 Map<Quaternion<typename D8::Scalar>> mq12(&q12(0));
463
464 between(p1, mq1, p2, mq2, p12, mq12);
465}
466
467template <typename D1, typename D2, typename D3>
468inline void between(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& d12)
469{
473
474 Map<const Matrix<typename D1::Scalar, 3, 1>> p1(&d1(0));
475 Map<const Quaternion<typename D1::Scalar>> q1(&d1(3));
476 Map<const Matrix<typename D2::Scalar, 3, 1>> p2(&d2(0));
477 Map<const Quaternion<typename D2::Scalar>> q2(&d2(3));
478 Map<Matrix<typename D3::Scalar, 3, 1>> p12(&d12(0));
479 Map<Quaternion<typename D3::Scalar>> q12(&d12(3));
480
481 between(p1, q1, p2, q2, p12, q12);
482}
483
484template <typename D1, typename D2>
485inline Matrix<typename D1::Scalar, 7, 1> between(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
486{
487 Matrix<typename D1::Scalar, 7, 1> d12;
488 between(d1, d2, d12);
489 return d12;
490}
491
492inline void between(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& x12)
493{
494 x12['P'].resize(3);
495 x12['O'].resize(4);
496 between(x1.at('P'), x1.at('O'), x2.at('P'), x2.at('O'), x12['P'], x12['O']);
497}
498
500{
501 VectorComposite x12;
502 between(x1, x2, x12);
503 return x12;
504}
505
507// EXP
508
509template <typename D1, typename D2, typename D3, typename D4>
510inline void exp(const MatrixBase<D1>& rho, const MatrixBase<D2>& theta, MatrixBase<D3>& p, QuaternionBase<D4>& q)
511{
515
516 // see [1] eqs. (174) and (145)
517 p = jac_SO3_left(theta) * rho;
518 q = exp_q(theta);
519}
520
521template <typename D1, typename D2, typename D3, typename D4>
522inline void exp(const MatrixBase<D1>& rho, const MatrixBase<D2>& theta, MatrixBase<D3>& p, MatrixBase<D4>& q)
523{
525
526 Map<Quaternion<typename D4::Scalar>> mq(&q(0));
527 exp(rho, theta, p, mq);
528}
529
530template <typename D1, typename D2>
531inline void exp(const MatrixBase<D1>& tau, MatrixBase<D2>& delta)
532{
535
536 Map<const Matrix<typename D1::Scalar, 3, 1>> rho(&tau(0));
537 Map<const Matrix<typename D1::Scalar, 3, 1>> theta(&tau(3));
538 Map<Matrix<typename D2::Scalar, 3, 1>> p(&delta(0));
539 Map<Quaternion<typename D2::Scalar>> q(&delta(3));
540
541 exp(rho, theta, p, q);
542}
543
544template <typename D>
545inline Matrix<typename D::Scalar, 7, 1> exp(const MatrixBase<D>& tau)
546{
547 Matrix<typename D::Scalar, 7, 1> delta;
548 exp(tau, delta);
549 return delta;
550}
551
552template <typename D1, typename D2, typename D3>
553inline void exp(const MatrixBase<D1>& tau, MatrixBase<D2>& delta, MatrixBase<D3>& J_delta_tau)
554{
557 MatrixSizeCheck<6, 6>::check(J_delta_tau);
558
559 typedef typename D1::Scalar T;
560
561 Matrix<T, 6, 1> tau_tmp = tau; // copy (tau and delta may alias)
562 Matrix<T, 3, 1> rho = tau_tmp.template head<3>();
563 Matrix<T, 3, 1> theta = tau_tmp.template tail<3>();
564 Matrix<T, 3, 3> Jl = jac_SO3_left(theta);
565 Matrix<T, 3, 1> p = Jl * rho;
566
567 /* Block-wise jacobian (additive position, local rotation), from the left Jacobian of SE(3) [Jl, Q; 0, Jl]:
568 * J_p_rho = Jl(theta)
569 * J_p_theta = Q(rho, theta) - [p]x * Jl(theta)
570 * J_o_rho = 0
571 * J_o_theta = Jr(theta)
572 */
573 J_delta_tau.setZero();
574 J_delta_tau.template topLeftCorner<3, 3>() = Jl;
575 J_delta_tau.template topRightCorner<3, 3>() = Q_helper(rho, theta) - skew(p) * Jl;
576 J_delta_tau.template bottomRightCorner<3, 3>() = jac_SO3_right(theta);
577
578 exp(tau_tmp, delta);
579}
580
581inline void exp(const VectorComposite& tau, VectorComposite& delta)
582{
583 // temporaries: tangent and manifold 'O' have different sizes (tau and delta may be the same object)
584 Vector3d p;
585 Vector4d q;
586 exp(tau.at('P'), tau.at('O'), p, q);
587 delta['P'] = p;
588 delta['O'] = q;
589}
590
592{
593 VectorComposite delta;
594 exp(tau, delta);
595 return delta;
596}
597
599// LOG
600
601template <typename D1, typename D2, typename D3, typename D4>
602inline void log(const MatrixBase<D1>& p, const QuaternionBase<D2>& q, MatrixBase<D3>& rho, MatrixBase<D4>& theta)
603{
607
608 // see [1] eqs. (173) and (146)
609 Matrix<typename D2::Scalar, 3, 1> th = log_q(q);
610 rho = jac_SO3_left_inv(th) * p;
611 theta = th;
612}
613
614template <typename D1, typename D2, typename D3, typename D4>
615inline void log(const MatrixBase<D1>& p, const MatrixBase<D2>& q, MatrixBase<D3>& rho, MatrixBase<D4>& theta)
616{
618
619 Map<const Quaternion<typename D2::Scalar>> mq(&q(0));
620 log(p, mq, rho, theta);
621}
622
623template <typename D1, typename D2>
624inline void log(const MatrixBase<D1>& delta, MatrixBase<D2>& tau)
625{
628
629 Map<const Matrix<typename D1::Scalar, 3, 1>> p(&delta(0));
630 Map<const Quaternion<typename D1::Scalar>> q(&delta(3));
631 Map<Matrix<typename D2::Scalar, 3, 1>> rho(&tau(0));
632 Map<Matrix<typename D2::Scalar, 3, 1>> theta(&tau(3));
633
634 log(p, q, rho, theta);
635}
636
637template <typename D>
638inline Matrix<typename D::Scalar, 6, 1> log(const MatrixBase<D>& delta)
639{
640 Matrix<typename D::Scalar, 6, 1> tau;
641 log(delta, tau);
642 return tau;
643}
644
645template <typename D1, typename D2, typename D3>
646inline void log(const MatrixBase<D1>& delta, MatrixBase<D2>& tau, MatrixBase<D3>& J_tau_delta)
647{
650 MatrixSizeCheck<6, 6>::check(J_tau_delta);
651
652 typedef typename D1::Scalar T;
653
654 Matrix<T, 6, 1> tau_tmp;
655 log(delta, tau_tmp);
656 Matrix<T, 3, 1> rho = tau_tmp.template head<3>();
657 Matrix<T, 3, 1> theta = tau_tmp.template tail<3>();
658 Matrix<T, 3, 1> p = delta.template head<3>();
659
660 /* Block-wise jacobian (additive position, local rotation): inverse of the jacobian of exp()
661 * J_exp = [A, B; 0, C] with A = Jl(theta), B = Q(rho, theta) - [p]x * Jl(theta), C = Jr(theta)
662 * J_log = [A.inv, -A.inv * B * C.inv; 0, C.inv]
663 */
664 Matrix<T, 3, 3> Jl_inv = jac_SO3_left_inv(theta);
665 Matrix<T, 3, 3> Jr_inv = jac_SO3_right_inv(theta);
666 Matrix<T, 3, 3> B = Q_helper(rho, theta) - skew(p) * jac_SO3_left(theta);
667
668 J_tau_delta.setZero();
669 J_tau_delta.template topLeftCorner<3, 3>() = Jl_inv;
670 J_tau_delta.template topRightCorner<3, 3>() = -Jl_inv * B * Jr_inv;
671 J_tau_delta.template bottomRightCorner<3, 3>() = Jr_inv;
672
673 tau = tau_tmp;
674}
675
676inline void log(const VectorComposite& delta, VectorComposite& tau)
677{
678 // temporaries: tangent and manifold 'O' have different sizes (tau and delta may be the same object)
679 Vector3d rho, theta;
680 log(delta.at('P'), delta.at('O'), rho, theta);
681 tau['P'] = rho;
682 tau['O'] = theta;
683}
684
686{
687 VectorComposite tau;
688 log(delta, tau);
689 return tau;
690}
691
693// PLUS (block-wise)
694
695template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
696inline void plus(const MatrixBase<D1>& p1,
697 const QuaternionBase<D2>& q1,
698 const MatrixBase<D4>& p2,
699 const MatrixBase<D5>& o2,
700 MatrixBase<D7>& plus_p,
701 QuaternionBase<D8>& plus_q)
702{
707
708 plus_p = p1 + p2;
709 plus_q = q1 * exp_q(o2);
710}
711
712template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
713inline void plus(const MatrixBase<D1>& p1,
714 const MatrixBase<D2>& q1,
715 const MatrixBase<D4>& p2,
716 const MatrixBase<D5>& o2,
717 MatrixBase<D7>& plus_p,
718 MatrixBase<D8>& plus_q)
719{
722
723 Map<const Quaternion<typename D2::Scalar>> q1m(&q1(0));
724 Map<Quaternion<typename D8::Scalar>> plus_qm(&plus_q(0));
725
726 plus(p1, q1m, p2, o2, plus_p, plus_qm);
727}
728
729template <typename D1, typename D2, typename D3>
730inline void plus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& d_plus)
731{
735
736 Map<const Matrix<typename D1::Scalar, 3, 1>> p1(&d1(0));
737 Map<const Quaternion<typename D1::Scalar>> q1(&d1(3));
738 Map<const Matrix<typename D2::Scalar, 3, 1>> p2(&d2(0));
739 Map<const Matrix<typename D2::Scalar, 3, 1>> o2(&d2(3));
740 Map<Matrix<typename D3::Scalar, 3, 1>> p_p(&d_plus(0));
741 Map<Quaternion<typename D3::Scalar>> q_p(&d_plus(3));
742
743 plus(p1, q1, p2, o2, p_p, q_p);
744}
745
746template <typename D1, typename D2>
747inline Matrix<typename D1::Scalar, 7, 1> plus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
748{
749 Matrix<typename D1::Scalar, 7, 1> d_plus;
750 plus(d1, d2, d_plus);
751 return d_plus;
752}
753
754inline void plus(const VectorComposite& x, const VectorComposite& tau, VectorComposite& res)
755{
756 res['P'].resize(3);
757 res['O'].resize(4);
758 plus(x.at('P'), x.at('O'), tau.at('P'), tau.at('O'), res['P'], res['O']);
759}
760
762{
763 VectorComposite res;
764 plus(x, tau, res);
765 return res;
766}
767
769// MINUS (block-wise)
770
771template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
772inline void minus(const MatrixBase<D1>& p1,
773 const QuaternionBase<D2>& q1,
774 const MatrixBase<D4>& p2,
775 const QuaternionBase<D5>& q2,
776 MatrixBase<D7>& pd,
777 MatrixBase<D8>& od)
778{
783
784 pd = p2 - p1;
785 od = log_q(q1.conjugate() * q2);
786}
787
788template <typename D1, typename D2, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9>
789inline void minus(const MatrixBase<D1>& p1,
790 const QuaternionBase<D2>& q1,
791 const MatrixBase<D4>& p2,
792 const QuaternionBase<D5>& q2,
793 MatrixBase<D6>& pd,
794 MatrixBase<D7>& od,
795 MatrixBase<D8>& J_do_q1,
796 MatrixBase<D9>& J_do_q2)
797{
798 minus(p1, q1, p2, q2, pd, od);
799
800 J_do_q1 = -jac_SO3_left_inv(od);
801 J_do_q2 = jac_SO3_right_inv(od);
802}
803
804template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
805inline void minus(const MatrixBase<D1>& p1,
806 const MatrixBase<D2>& q1,
807 const MatrixBase<D4>& p2,
808 const MatrixBase<D5>& q2,
809 MatrixBase<D7>& pd,
810 MatrixBase<D8>& od)
811{
814
815 Map<const Quaternion<typename D2::Scalar>> mq1(&q1(0));
816 Map<const Quaternion<typename D5::Scalar>> mq2(&q2(0));
817
818 minus(p1, mq1, p2, mq2, pd, od);
819}
820
821template <typename D1, typename D2, typename D3>
822inline void minus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& err)
823{
827
828 Map<const Matrix<typename D1::Scalar, 3, 1>> p1(&d1(0));
829 Map<const Quaternion<typename D1::Scalar>> q1(&d1(3));
830 Map<const Matrix<typename D2::Scalar, 3, 1>> p2(&d2(0));
831 Map<const Quaternion<typename D2::Scalar>> q2(&d2(3));
832 Map<Matrix<typename D3::Scalar, 3, 1>> pd(&err(0));
833 Map<Matrix<typename D3::Scalar, 3, 1>> od(&err(3));
834
835 minus(p1, q1, p2, q2, pd, od);
836}
837
838template <typename D1, typename D2, typename D3, typename D4, typename D5>
839inline void minus(const MatrixBase<D1>& d1,
840 const MatrixBase<D2>& d2,
841 MatrixBase<D3>& dif,
842 MatrixBase<D4>& J_diff_d1,
843 MatrixBase<D5>& J_diff_d2)
844{
850
851 Map<const Matrix<typename D1::Scalar, 3, 1>> p1(&d1(0));
852 Map<const Quaternion<typename D1::Scalar>> q1(&d1(3));
853 Map<const Matrix<typename D2::Scalar, 3, 1>> p2(&d2(0));
854 Map<const Quaternion<typename D2::Scalar>> q2(&d2(3));
855 Map<Matrix<typename D3::Scalar, 3, 1>> pd(&dif(0));
856 Map<Matrix<typename D3::Scalar, 3, 1>> od(&dif(3));
857
858 Matrix<typename D4::Scalar, 3, 3> J_do_q1, J_do_q2;
859
860 minus(p1, q1, p2, q2, pd, od, J_do_q1, J_do_q2);
861
862 /* d = minus(d1, d2) is
863 * pd = p2 - p1
864 * od = Log(q1.conj * q2)
865 *
866 * With trivial Jacobians for p and dv, and:
867 * J_do_q1 = - J_l_inv(theta)
868 * J_do_q2 = J_r_inv(theta)
869 */
870 J_diff_d1 = -Matrix<typename D4::Scalar, 6, 6>::Identity(); // d(p2 - p1) / d(p1) = - Identity
871 J_diff_d1.block(3, 3, 3, 3) = J_do_q1; // d(R1.tr*R2) / d(R1) = - J_l_inv(theta)
872
873 J_diff_d2.setIdentity(6, 6); // d(R1.tr*R2) / d(R2) = Identity
874 J_diff_d2.block(3, 3, 3, 3) = J_do_q2; // d(R1.tr*R2) / d(R1) = J_r_inv(theta)
875}
876
877template <typename D1, typename D2>
878inline Matrix<typename D1::Scalar, 6, 1> minus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
879{
880 Matrix<typename D1::Scalar, 6, 1> ret;
881 minus(d1, d2, ret);
882 return ret;
883}
884
885inline void minus(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& res)
886{
887 // temporaries: tangent and manifold 'O' have different sizes (res and x1 or x2 may be the same object)
888 Vector3d pd, od;
889 minus(x1.at('P'), x1.at('O'), x2.at('P'), x2.at('O'), pd, od);
890 res['P'] = pd;
891 res['O'] = od;
892}
893
895{
896 VectorComposite res;
897 minus(x1, x2, res);
898 return res;
899}
900
902// INTERPOLATE
903
904template <typename D1, typename D2, typename D3>
905inline void interpolate(const MatrixBase<D1>& d1,
906 const MatrixBase<D2>& d2,
907 const typename D1::Scalar& t,
908 MatrixBase<D3>& ret)
909{
913
914 Matrix<typename D1::Scalar, 7, 1> dd = between(d1, d2);
915
916 Matrix<typename D1::Scalar, 6, 1> tau = t * log(dd);
917
918 ret = compose(d1, exp(tau));
919}
920
921template <typename D1, typename D2>
922inline Matrix<typename D1::Scalar, 7, 1> interpolate(const MatrixBase<D1>& d1,
923 const MatrixBase<D2>& d2,
924 const typename D1::Scalar& t)
925{
926 Matrix<typename D1::Scalar, 7, 1> ret;
927 interpolate(d1, d2, t, ret);
928 return ret;
929}
930
931inline void interpolate(const VectorComposite& x1, const VectorComposite& x2, const double& t, VectorComposite& res)
932{
933 VectorComposite tau = log(between(x1, x2));
934 tau['P'] *= t;
935 tau['O'] *= t;
936 compose(x1, exp(tau), res);
937}
938
939inline VectorComposite interpolate(const VectorComposite& x1, const VectorComposite& x2, const double& t)
940{
941 VectorComposite res;
942 interpolate(x1, x2, t, res);
943 return res;
944}
945
947// HOMOGENEOUS MATRIX
948
949template <typename D1, typename D2>
950inline void toSE3(const MatrixBase<D1>& pose, MatrixBase<D2>& SE3)
951{
954
955 typedef typename D1::Scalar T;
956
957 SE3.template block<3, 1>(0, 3) = pose.template head<3>();
958 SE3.template block<3, 3>(0, 0) = q2R(pose.template tail<4>());
959 SE3.template block<1, 3>(3, 0).setZero();
960 SE3(3, 3) = (T)1.0;
961}
962
963template <typename D>
964inline Matrix<typename D::Scalar, 4, 4> toSE3(const MatrixBase<D>& pose)
965{
966 Matrix<typename D::Scalar, 4, 4> SE3;
967 toSE3(pose, SE3);
968 return SE3;
969}
970
971} // namespace SE3
972} // namespace wolf
Definition: vector_composite.h:27
Namespace extending Eigen definitions.
Definition: wolf.h:94
void interpolate(const MatrixBase< D1 > &d1, const MatrixBase< D2 > &d2, const typename D1::Scalar &t, MatrixBase< D3 > &ret)
Definition: SE3.h:905
Matrix< typename D1::Scalar, 3, 3 > Q_helper(const MatrixBase< D1 > &v, const MatrixBase< D2 > &w)
Q matrix of the left Jacobian of SE(3), with v the linear and w the angular parts of the tangent vect...
Definition: SE3.h:85
Matrix< typename D::Scalar, 6, 6 > jac_SE3_right_inv(const MatrixBase< D > &tangent)
Inverse of the right Jacobian of SE(3), with tangent = [rho, theta].
Definition: SE3.h:172
void identity(MatrixBase< D1 > &p, QuaternionBase< D2 > &q)
Definition: SE3.h:181
void plus(const MatrixBase< D1 > &p1, const QuaternionBase< D2 > &q1, const MatrixBase< D4 > &p2, const MatrixBase< D5 > &o2, MatrixBase< D7 > &plus_p, QuaternionBase< D8 > &plus_q)
Definition: SE3.h:696
void log(const MatrixBase< D1 > &p, const QuaternionBase< D2 > &q, MatrixBase< D3 > &rho, MatrixBase< D4 > &theta)
Definition: SE3.h:602
Matrix< typename D::Scalar, 6, 6 > jac_SE3_right(const MatrixBase< D > &tangent)
Right Jacobian of SE(3), with tangent = [rho, theta].
Definition: SE3.h:143
void minus(const MatrixBase< D1 > &p1, const QuaternionBase< D2 > &q1, const MatrixBase< D4 > &p2, const QuaternionBase< D5 > &q2, MatrixBase< D7 > &pd, MatrixBase< D8 > &od)
Definition: SE3.h:772
void compose(const MatrixBase< D1 > &p1, const QuaternionBase< D2 > &q1, const MatrixBase< D4 > &p2, const QuaternionBase< D5 > &q2, MatrixBase< D7 > &pc, QuaternionBase< D8 > &qc)
Definition: SE3.h:296
VectorComposite identityComposite()
Definition: SE3.h:224
Matrix< typename D::Scalar, 6, 6 > jac_SE3_left_inv(const MatrixBase< D > &tangent)
Inverse of the left Jacobian of SE(3), with tangent = [rho, theta].
Definition: SE3.h:151
void exp(const MatrixBase< D1 > &rho, const MatrixBase< D2 > &theta, MatrixBase< D3 > &p, QuaternionBase< D4 > &q)
Definition: SE3.h:510
void toSE3(const MatrixBase< D1 > &pose, MatrixBase< D2 > &SE3)
Definition: SE3.h:950
void inverse(const MatrixBase< D1 > &p, const QuaternionBase< D2 > &q, MatrixBase< D4 > &ip, QuaternionBase< D5 > &iq)
Definition: SE3.h:235
Matrix< typename D::Scalar, 6, 6 > jac_SE3_left(const MatrixBase< D > &tangent)
Left Jacobian of SE(3), with tangent = [rho, theta].
Definition: SE3.h:122
void between(const MatrixBase< D1 > &p1, const QuaternionBase< D2 > &q1, const MatrixBase< D4 > &p2, const QuaternionBase< D5 > &q2, MatrixBase< D7 > &p12, QuaternionBase< D8 > &q12)
Definition: SE3.h:433
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:641
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:617
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:626
Definition: capture_base.h:23
Eigen::Matrix< typename Derived::Scalar, 3, 3 > q2R(const Eigen::QuaternionBase< Derived > &_q)
quaternion to rotation matrix conversion
Definition: rotations.h:109
Eigen::Matrix< typename Derived::Scalar, 3, 3 > jac_SO3_right_inv(const Eigen::MatrixBase< Derived > &_theta)
Compute Jrinv (inverse of Right Jacobian which corresponds to the jacobian of log) Right Jacobian for...
Definition: rotations.h:463
Eigen::Quaternion< typename Derived::Scalar > exp_q(const Eigen::MatrixBase< Derived > &_v)
Quaternion exponential map.
Definition: rotations.h:258
Eigen::Matrix< typename Derived::Scalar, 3, 3 > jac_SO3_left(const Eigen::MatrixBase< Derived > &_theta)
Compute Jl (Left Jacobian) Left Jacobian for exp map in SO(3) - equation (10.86) and following equati...
Definition: rotations.h:497
Eigen::Matrix< typename Derived::Scalar, 3, 3 > jac_SO3_right(const Eigen::MatrixBase< Derived > &_theta)
Compute Jr (Right Jacobian) Right Jacobian for exp map in SO(3) - equation (10.86) and following equa...
Definition: rotations.h:423
Eigen::Matrix< typename Derived::Scalar, 3, 1 > log_q(const Eigen::QuaternionBase< Derived > &_q)
Quaternion logarithmic map.
Definition: rotations.h:287
Eigen::Matrix< typename Derived::Scalar, 3, 3 > jac_SO3_left_inv(const Eigen::MatrixBase< Derived > &_theta)
Compute Jl_inv (inverse of Left Jacobian which corresponds to the jacobian of log) Left Jacobian for ...
Definition: rotations.h:536
Eigen::Matrix< typename Derived::Scalar, 3, 3 > skew(const Eigen::MatrixBase< Derived > &_v)
Skew symmetric matrix.
Definition: rotations.h:70
static void check(const Eigen::MatrixBase< T > &t)
Assert matrix size dynamically or statically.
Definition: eigen_assert.h:93